#include "fxcc/core/graph/opengl3/SkyboxEffect.h"
#include "fxcc/core/graph/common/Geometry.h"
#include "mustache.hpp"

fxcc::graph::opengl3::SkyboxEffect::SkyboxEffect()
    :m_FragMain(GetDefaultFragCode())
{
    Init();
}

fxcc::graph::opengl3::SkyboxEffect::SkyboxEffect(const std::string& fragMain)
    :m_FragMain(fragMain)
{

    Init();

}

void fxcc::graph::opengl3::SkyboxEffect::Init()
{
    m_Shader = std::make_shared<fxcc::graph::opengl3::Shader>(GetVertCode().c_str(), GetFragCode().c_str());
    m_SkyboxMesh = std::make_shared<fxcc::graph::opengl3::MeshJack>(fxcc::graph::common::Geometry::CreateBox());
    // m_RasterizerDesc.enableCullFace = false;
    m_PipeLineType.m_DepthStencilType = fxcc::graph::common::DepthStencilType::_DEPTH_LEQUAL_STENCIL_NONE;
    m_PipeLineType.m_RasterizerType = fxcc::graph::common::RasterizerType::_NONE_;

}

void fxcc::graph::opengl3::SkyboxEffect::Begin()
{
    fxcc::graph::common::EffectBase::Begin();
    fxcc::graph::opengl3::RenderStates::Inst().Clear(m_PipeLineType);
    glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
    //glDepthMask(false);

    m_Shader->Use();

}

void fxcc::graph::opengl3::SkyboxEffect::End()
{
    //glDepthMask(true);

}

std::string fxcc::graph::opengl3::SkyboxEffect::GetFragCode()
{
    kainjow::mustache::mustache m1(GetFragTemp());

    kainjow::mustache::data d1;
    d1.set("fragMain", m_FragMain);
    d1.set("versionStr", fxcc::graph::opengl3::IBuffers::GetVersionStr());

    fxcc::graph::common::Effect3d::PassData;

    return m1.render(d1);
}

std::string fxcc::graph::opengl3::SkyboxEffect::GetVertCode()
{
    kainjow::mustache::mustache m1 = R"(
{{{versionStr}}}
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoord;
layout (location = 3) in vec3 aTangents;
layout (location = 4) in vec3 aBigTangents;

out vec3 localPos;

{{{uniform3dPart}}}

void main()
{
    localPos = aPos;

    vec4 clipPos = passData.proj * passData.skyboxView * vec4(aPos, 1.0);

    gl_Position=clipPos.xyww;
}


)";

    kainjow::mustache::data d1;
    d1.set("versionStr", fxcc::graph::opengl3::IBuffers::GetVersionStr());
    d1.set("uniform3dPart", fxcc::graph::opengl3::IBuffers::GetUniformPart3d());
    std::string vCode = m1.render(d1);
    return vCode;
}

std::string fxcc::graph::opengl3::SkyboxEffect::GetFragTemp()
{
    const std::string fCode = R"(

{{{versionStr}}}

in vec3 localPos;
uniform bool gamma;

{{fragMain}}
)";
    return fCode;
}

std::string fxcc::graph::opengl3::SkyboxEffect::GetDefaultFragCode()
{
    std::string res = R"(
out vec4 FragColor;

uniform samplerCube skybox;

void main()
{    
    vec3 color_rgb = texture(skybox, localPos).rgb;
    //envColor = envColor / (envColor + vec3(1.0));
    //envColor = pow(envColor, vec3(1.0 / 2.2));

    if(gamma)
    {
        color_rgb=color_rgb/ (color_rgb+vec3(1.0f));
        color_rgb =pow(color_rgb, vec3(1.0f/2.0f));
    }
    FragColor=vec4(color_rgb,1.0f);
}
)";

    return res;
}
